package com.lenovo.nova.util;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Random;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.PowerManager;
import android.os.SystemProperties;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;

import com.lenovo.nova.util.collection.Collections;
import com.lenovo.nova.util.debug.LogcatShowWindowManager;
import com.lenovo.nova.util.debug.MyOldLog;
import com.lenovo.nova.util.debug.ObjectUtil;
import com.lenovo.nova.util.fragment.BaseFragment;
import com.lenovo.nova.util.fragment.FragmentOperator;
import com.lenovo.nova.utils.R;
import com.lenovo.nova.widget.dialog.BaseDialogFragment;

/**
 * 不放到debug包下，因为需要在BaseActivity 一个包下.
 * 运行过程只有一个实例，自己构造的会没有效果
 *
 * @author scenic
 */

public class DebugUtil {

    /**
     * the value can be set by dumpsys
     */
    public static int debug_integer_1 = 0;

    public static int debugIntValue = 1;

    public static String[] allInputCmd;

    private static Activity mContext;

    private static Random mRandom = new Random();

    private OnDumpExecuteListener mListener;

    private static int mRandomColor[] = {Color.BLUE, Color.CYAN, Color.DKGRAY, Color.GREEN, Color.LTGRAY, Color.RED, Color.YELLOW,};

    //用来显示用户自定义的帮助命令
    private List<Object> mCustomCmd = new ArrayList<Object>();

    public static Bitmap getBitmapByColor(int color, int width, int height) {
        Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        canvas.drawColor(color);
        return bitmap;
    }

    private DebugUtil() {

    }

    public static void bitMapDrawableToFile(Drawable drawable, String path) {
        BitmapDrawable bmd = (BitmapDrawable) drawable;
        Bitmap bm = bmd.getBitmap();
        writeBitmapToFile(path, bm);
    }

    private static void writeBitmapToFile(String path, Bitmap bm) {
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(path);
        } catch (FileNotFoundException e) {
            MyOldLog.e(e);
            e.printStackTrace();
        }
        bm.compress(CompressFormat.PNG, 100, out);

        try {
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void drawableToFile(Drawable drawable, String path) {
        Bitmap bitmap = Bitmap.createBitmap(183, 183, Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.draw(canvas);
        writeBitmapToFile(path, bitmap);
    }

    private int cmdIndex = 0;


    public DebugUtil addCustomCmd(Object... obj) {
        for (Object object : obj) {
            mCustomCmd.add(object);
        }
        return this;
    }

    public int nextCmdValueAsInt() {
        int value = 0;
        String number = null;
        try {
            number = nextCmdValue();
            value = Integer.parseInt(number);
        } catch (NumberFormatException e) {
            print("NumberFormat Error " + number);
            e.printStackTrace();
        }
        return value;
    }

    public String nextCmdValue() {
        if (allInputCmd == null) {
            return "";
        }
        String temp;
        try {
            temp = allInputCmd[cmdIndex];
            cmdIndex++;
        } catch (Exception e) {
            return null;
        }
        if (temp == null) {
            return "";
        }
        return temp;
    }


    enum CmdType  {
        debug_getVersion,
        debug_switch,
        debug_init_view_group,
        debug_get_currentFocus_view,
        debug_get_focusView_next_focusId,
        debug_view_hierarchy,
        debug_view_all,
        debug_view_pick,
        save_value_put,
        save_value_get,
        save_value_remove,
        show_color_view,
        show_fragmentInfo,
        setSource,
        getSource,
        changeBrand,
        hideIME,
        isIMEShow,
        debug_channel_getChannelValue,
        debug_dtv_getRFChannel,
        debug_bluetooth,
        debug_clear_fota,
        debug_inputmethod_is_pop,
        fragment_execute_current,
        fragment_list_all,
        fragment_dismiss_dialog,
        execute_update,
        debug_set_integer_1,
        showLogcat,
        window_show_dim,
        window_set_dim,
        test
    }

    private HashMap<String, ViewGroup> mViewGroups = new HashMap<String, ViewGroup>();
    private View mCurrentView = null;
    private Writer mWrite = null;

    public DebugUtil setOnDumpExecuteListener(OnDumpExecuteListener l) {
        mListener = l;
        return this;
    }

    void dump(String prefix, FileDescriptor fd, final PrintWriter writer, String[] args) {
        allInputCmd = args;
        mWrite = writer;

        try {
            String cmdType = nextCmdValue();

            //add child listener
            if (mListener != null) {
                try {
                    if (mListener.onDumpExecute(this, prefix, fd, writer, args, cmdType)) {
                        reset();
                        return;
                    }
                } catch (Exception e) {
                    print("===============" + e.toString() +"============");
                    showHelp(writer, mCustomCmd);
                    print("===============" + e.toString() +"============");
                }
            }

            //if want help
            if (cmdType.equals("help")) {
                showHelp(writer);
                return;
            }

            CmdType type;
            try {
                type = CmdType.valueOf(cmdType);
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }
            switch (type) {
                case debug_switch:
                    // open or close debug
                    String value = nextCmdValue();
                    if (value.equals("true")) {
                        Applications.isInDebugMode = true;
                    } else {
                        Applications.isInDebugMode = false;
                    }
                   new SaveValue(mContext).save(Constant.Debug.KEY_DEBUG_SWITCH, value);
                    writer.append("current debug mode is " + Applications.get(mContext).isDebugMode() + " \n").flush();
                    break;
                case debug_get_currentFocus_view:
                    mCurrentView = mContext.getCurrentFocus();
                    if (mCurrentView != null) {
                        writer.append("current view is " + mCurrentView + " isEnable " + mCurrentView.isEnabled() + "  isFocusable " + mCurrentView.isFocusable() + "\n").flush();
                        writer.append("current view id is " + findRDeclaredNameByValue(mCurrentView.getId()) + "  " + mCurrentView.getId() + "\n").flush();
                    } else {
                        print("not view get focus");
                    }

                    List<BaseDialogFragment> child = BaseDialogFragment.getAllInstance();
                    if(child != null && child.size() > 0){

                        BaseDialogFragment tmp = child.get(child.size() - 1);
                        tmp.debugFocus(tmp.getView());
                    }

                    break;
                case debug_get_focusView_next_focusId:
                    mCurrentView = mContext.getCurrentFocus();
                    print("focus view is " + mCurrentView + "  " + findRDeclaredNameByValue(mCurrentView.getId()));
                    print("next up id is " + mCurrentView.getNextFocusUpId());
                    print("next down id is " + mCurrentView.getNextFocusDownId());
                    print("next left id is " + mCurrentView.getNextFocusLeftId());
                    print("next right id is " + mCurrentView.getNextFocusRightId());
                    break;
                case debug_view_all:
                    String str = ObjectUtil.showObjectField(mCurrentView);
                    print(str);
                case debug_view_pick:
                    String log = ObjectUtil.showObjectField(mCurrentView, nextCmdValue());
                    print(log);
                    break;
                case debug_view_hierarchy:
                    Class<?> currentClass = mCurrentView.getClass();
                    Class<?> viewClass = null;

                    String lookAtView = "android.view.View";
                    try {
                        lookAtView = nextCmdValue();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    do {
                        String className = currentClass.getName();
                        print(className);
                        if (className.equals(lookAtView)) {
                            viewClass = currentClass;
                        }
                    } while ((currentClass = currentClass.getSuperclass()) != null);

                    // log = ObjectUtil.showObjectField(viewClass, mCurrentView,
                    // null);
                    print("reflect view is " + viewClass);
                    // print(log);
                    break;
                case debug_init_view_group:
                    mCurrentView = mContext.getCurrentFocus();
                    ViewGroup tempGroup = (ViewGroup) mCurrentView.getParent();
                    if (tempGroup != null) {
                        int index = 1;
                        mViewGroups.put(index + "", tempGroup);
                        print("key:1 " + tempGroup);

                        while (tempGroup != null) {
                            tempGroup = (ViewGroup) tempGroup.getParent();
                            mViewGroups.put(++index + "", tempGroup);
                            print(index + ":" + tempGroup);
                        }
                    } else {
                        print("view group of " + mCurrentView + " is null");
                    }
                    break;
                case save_value_put:
                {
                    String valueType = nextCmdValue();
                    print("value type is " + valueType);

                    if(valueType.equals("int")){
                        new SaveValue(mContext).putInt(nextCmdValue(),nextCmdValueAsInt());
                        print("save int value ok " );
                    }

                    if(valueType.equals("string")){
                        new SaveValue(mContext).putString(nextCmdValue(), nextCmdValue());
                        print("save String value ok " );
                    }

                }


                    break;
                case save_value_get:
                {
                    String valuetype = nextCmdValue();
                    String key = nextCmdValue();
                    if(valuetype.equals("int")){
                        print("the int value is " + new SaveValue(mContext).getInt(key, -1));
                    }
                    if(valuetype.equals("string")){
                        print("the int value is " + new SaveValue(mContext).getString(key));
                    }
                }
                    break;
                case save_value_remove:
                    new SaveValue(mContext).remove(nextCmdValue());
                    break;
                case show_color_view:
                    dealShowColor();
                    break;

                case test:
                    break;

                case show_fragmentInfo:
//				print(SystemFragment.getInstance(mContext).getFragmentInfo());
                    break;
                case changeBrand:
                    SystemProperties.set("ro.product.brand", nextCmdValue());
                    print("ro.product.brand is " + SystemProperties.get("ro.product.brand"));
                    break;
                case hideIME: {
                    InputMethodManager manager = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
                    manager.toggleSoftInput(0, 0);
                    break;
                }
                case isIMEShow: {
                    mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
                }

                break;

                case debug_clear_fota:
                    File recoveryFile = new File("/cache/recovery/update.zip");
                    recoveryFile.delete();
                    break;
                case debug_inputmethod_is_pop:
                    break;
                case debug_getVersion:
                    PackageInfo info = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0);
                    print("versionCode " + info.versionCode + " verName " + info.versionName);
                    break;
                case fragment_execute_current:
                    ArrayList<Fragment> list = FragmentOperator.FragmentHelper.getFragmentOperator().getFragmentList();
//                    com.lenovo.nova.util.fragment.BaseFragment fragment =
//                            (BaseFragment) FragmentOperator.FragmentHelper.getFragmentOperator().
//                                    getCurrentFragmentFilterDialogFragment();
                    Fragment fragment = list.get(list.size() - 1);
                    if (fragment != null) {
                        if(fragment instanceof  BaseFragment){
                            ((BaseFragment)fragment).onDumpExecute(this, nextCmdValue());
                        }else if(fragment instanceof BaseDialogFragment){
                            ((BaseDialogFragment) fragment).onDumpExecute(this,nextCmdValue());
                        }else{
                            fragment.dump(prefix,fd,writer,args);
                        }
                    }

                    break;
                case execute_update:
                    PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
                    pm.setNextBootMode("factory2");
                    pm.reboot("factory2");
                    break;
                case debug_set_integer_1:
                    debug_integer_1 = nextCmdValueAsInt();
                    break;
                case showLogcat:
                    new LogcatShowWindowManager(mContext).showLogcatWindowManager();
                    break;
                case fragment_dismiss_dialog:
                    FragmentOperator.FragmentHelper.getFragmentOperator().init(mContext);
                    ArrayList<Fragment> list1 = FragmentOperator.FragmentHelper.getFragmentOperator().getFragmentList();
                    for (int i = 0; i < list1.size(); i++) {
                        Fragment tmp = list1.get(i);
                        if(tmp instanceof BaseDialogFragment){
                            ((BaseDialogFragment) tmp).dismiss();
                        }
                    }
                    break;
                case fragment_list_all:

                    int count = mContext.getFragmentManager().getBackStackEntryCount();
                    print("count " + count);
                    for (int i = 0; i < count; i++) {
                        FragmentManager.BackStackEntry entity = mContext.getFragmentManager().getBackStackEntryAt(i);
                        print(entity.getName() + " " + entity.getId());
                    }


//            ArrayList<Fragment> mActive;
//            ArrayList<Fragment> mAdded;
                    try {
                        Field mAddMethod = mContext.getFragmentManager().getClass().getDeclaredField("mAdded");
                        mAddMethod.setAccessible(true);
                        ArrayList<Fragment> mAdd = (ArrayList<Fragment>) mAddMethod.get(mContext.getFragmentManager());
                        print(mAdd.toString());
                    } catch (NoSuchFieldException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }

                    try {
                        Field mAddMethod = mContext.getFragmentManager().getClass().getDeclaredField("mActive");
                        mAddMethod.setAccessible(true);
                        ArrayList<Fragment> mActive = (ArrayList<Fragment>) mAddMethod.get(mContext.getFragmentManager());
                        print(mActive.toString());
                    } catch (NoSuchFieldException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                    break;
                case window_show_dim:
                    float dimAmount = mContext.getWindow().getAttributes().dimAmount;
                    print("dimAmount " + dimAmount);
                    break;
                case window_set_dim:
                    WindowManager.LayoutParams att = mContext.getWindow().getAttributes();
                    att.flags|=WindowManager.LayoutParams.FLAG_DIM_BEHIND;

                    att.dimAmount = Float.valueOf(nextCmdValue());

                    mContext.getWindow().setAttributes(att);
                    break;
                default:
                    reset();
                    showHelp(writer);
//				mContext.superDump(prefix, fd, writer, args);
                    break;
            }

        } catch (Exception e) {
            showHelp(writer);
            print(e.toString());
            e.printStackTrace();
        } finally {
            reset();
        }
    }


    private void reset() {
        cmdIndex = 0;
    }

    private void dealShowColor() {
        String idStr = null;
        while ((idStr = nextCmdValue()) != null) {
            int id = mContext.getResources().getIdentifier(idStr, "id", mContext.getPackageName());
            mContext.findViewById(id).setBackgroundColor(getRandomColor());
        }
    }

    public static int getRandomColor() {
        return mRandomColor[mRandom.nextInt(mRandomColor.length)];
    }

    public void print(String str) {
        try {
            mWrite.append(str + "\n").flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void showHelp(final PrintWriter writer) {
        writer.append("Input Error \n").flush();
        for (CmdType cmd : CmdType.values()) {
            writer.append(cmd.toString() + "\n");
        }
        writer.flush();
    }

    private void showHelp(final PrintWriter writer, Collection<Object> obj) {
        writer.append("Input Error \n").flush();
        Collections.showCollection(obj, new Collections.OnShowCollectionHelper<Object>() {
            @Override
            public boolean onCloseInternalPrint() {
                return true;
            }

            @Override
            public void onItem(Object e) {
                writer.append(e.toString() + "\n");
            }

        });
        writer.flush();
    }

    private static DebugUtil instance;

    @Deprecated
    public static DebugUtil getInstance(Context context) {
        if (instance == null) {
            instance = new DebugUtil();
            mContext = (Activity) context;
        }
        return instance;
    }

    public static void headerResume(Context mContext2) {
        // SettingsApplication.get().launchFragmentByName(Common.class.getName());
//		SystemProperties.set("ro.mdf.d", "fd");
    }

    public static String findRDeclaredNameByValue(int value) {
        Class<?> allClassInR[] = R.class.getDeclaredClasses();
        try {
            for (Class<?> oneClass : allClassInR) {
                Field[] field = oneClass.getDeclaredFields();
                for (Field idField : field) {
                    idField.setAccessible(true);
                    int tempValue = 0;
                    try {
                        tempValue = (Integer) idField.get(oneClass);
                    } catch (Exception e) {
                    }
                    if (tempValue == value) {
                        return oneClass.getName() + "." + idField.getName();
                    }
                }
            }
        } catch (IllegalArgumentException e) {

        }
        return "NULL";
    }


    public interface OnDumpExecuteListener {
        boolean onDumpExecute(DebugUtil util,
                              String prefix, FileDescriptor fd, PrintWriter writer, String[] args, String cmdValue);
    }


}
